package x86;

import hex.Input;
import hex.Instruction;
import hex.Operand;
import hex.Operator;
import hex.Operand.ImmOperand;
import vm.Vm;

/**
 * Detector
 * @author qj 2009-8-1 18:06
 * 
 */
public class Detector {
	Input input = Input.getInstance();
	Disassembler disasm = Disassembler.getInstance();
	Vm vm = Vm.getInstance();

	final static boolean MATCHED = true;
	final static boolean NOT_MATCHED = false;
	boolean s, w;
	int modrm_reg, modrm_rm, modrm_mod, sib_scale, sib_index, sib_base;

	public boolean detect() {
		return NOT_MATCHED;
	};

	void init(int b, int b2) {
		s = (b >> 1 & 0x01) > 0;
		w = (b & 0x01) > 0;
		modrm_mod = b2 >> 6;
		modrm_reg = b2 >> 3 & 0x3;
		modrm_rm = b2 & 0x7;
		getSIB(b2);
	}

	void getSIB(int b) {
		sib_scale = b >> 6;
		sib_index = b >> 3 & 3;
		sib_base = b & 7;
	}

	/**
	 * decode mod/rm
	 * 
	 * @return operand
	 */
	public Operand decode_modrm() {
		if (modrm_mod == 3) // reg?
			return null;
		if (modrm_mod == 0 && modrm_rm == 5) // disp32?
			return new ImmOperand(input.getLEDWORD());

		int disp = 0;int disp_len = 0;
		if (modrm_mod == 1)
		{
			disp = input.getByte();
			disp_len=1;
		}
		else if (modrm_mod == 2)
		{
			disp = input.getLEDWORD();
			disp_len=4;
		}
		
		boolean hasDisplacement = (modrm_mod == 1 || modrm_mod == 2);

		if (modrm_rm == 4) {// [--][--]
			if (sib_index != 4) {// 100
				// t0 = EAX * 2^?
				new Instruction(Operator.MUL.INSTANCE,
						vm.GlobalRegister[sib_index], 1 << sib_scale,
						vm.TempRegister[0],0).Add();
				if (sib_base != 5) {// [EAX*2 + EDX]?
					// t0 = t0 + EDX
					new Instruction(Operator.ADD.INSTANCE, vm.TempRegister[0],
							vm.GlobalRegister[sib_base],0).Add();
				} else {
					if (modrm_mod == 0)// [scaled index] + disp32
					{
						new Instruction(Operator.ADD.INSTANCE,
								vm.TempRegister[0], input.getLEDWORD()).Add();
					} else// 01 [scaled index] + disp8 + [EBP] or
					// 10 [scaled index] + disp32 + [EBP]
					{
						new Instruction(Operator.ADD.INSTANCE,
								vm.TempRegister[0], vm.FP,0).Add();
						new Instruction(Operator.ADD.INSTANCE,
								vm.TempRegister[0], disp,disp_len).Add();
					}

					return Operand.RegFactory.getInstance().get(
							vm.TempRegister[0].getName());
				}

				if (hasDisplacement) // + disp?
				{
					new Instruction(Operator.ADD.INSTANCE, vm.TempRegister[0],
							disp,disp_len).Add();
				}

				return Operand.RegFactory.getInstance().get(
						vm.TempRegister[0].getName());
			} else // [sib_base]
			{
				if (hasDisplacement)// [sib_base] + disp?
				{
					new Instruction(Operator.ADD.INSTANCE,
							vm.GlobalRegister[sib_base], disp,
							vm.TempRegister[0],disp_len).Add();

					return Operand.RegFactory.getInstance().get(
							vm.TempRegister[0].getName());
				} else
					return Operand.RegFactory.getInstance().get(
							vm.TempRegister[modrm_rm].getName());
			}
		} else {
			if (hasDisplacement)// [EAX*4] + disp?
			{
				new Instruction(Operator.ADD.INSTANCE,
						vm.GlobalRegister[modrm_rm], disp, vm.TempRegister[0],disp_len)
						.Add();

				return Operand.RegFactory.getInstance().get(
						vm.TempRegister[0].getName());
			} else
				// [EAX*4]?
				return Operand.RegFactory.getInstance().get(
						vm.GlobalRegister[modrm_rm].getName());
		}
	}

}
